package com.company.emenu.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.company.emenu.exception.BeanAccessException;

/**
 * Java Bean 应用类 扩展Apache Commons BeanUtils, 提供一些反射方面缺失功能的封装.
 * 
 * @author laiqg
 * @author shizh
 * BeanUtils jar包导入错误是因为在.classpath中没有配置<classpathentry exported="true" kind="con" path="melibrary.com.genuitec.eclipse.cross.easystruts.eclipse.STRUTS13_CONTAINER"/>
 */
public class BeanUtils extends org.apache.commons.beanutils.BeanUtils {

	protected static final Log logger = LogFactory.getLog(BeanUtils.class);

	private BeanUtils() {
	}

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 * 
	 * @throws BeanAccessException
	 *             如果没有该Field时抛出.
	 */
	public static Field getDeclaredField(Object object, String propertyName)
			throws BeanAccessException {
		Assert.notNull(object);
		Assert.hasText(propertyName);
		return getDeclaredField(object.getClass(), propertyName);
	}

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 * 
	 * @throws BeanAccessException
	 *             如果没有该Field时抛出.
	 */
	public static Field getDeclaredField(Class clazz, String propertyName)
			throws BeanAccessException {
		Assert.notNull(clazz);
		Assert.hasText(propertyName);
		for (Class superClass = clazz; superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredField(propertyName);
			} catch (NoSuchFieldException e) {
				// Field不在当前类定义,继续向上转型
			}
		}
		throw new BeanAccessException("No such field: " + clazz.getName() + '.'
				+ propertyName);
	}

	/**
	 * 暴力获取对象变量值,忽略private,protected修饰符的限制.
	 * 
	 * @throws BeanAccessException
	 *             如果没有该Field时抛出.
	 */
	public static Object getPropertyValue(Object object, String propertyName)
			throws BeanAccessException {
		Assert.notNull(object);
		Assert.hasText(propertyName);

		try {
			PropertyDescriptor descriptor = new PropertyDescriptor(
					propertyName, object.getClass());
			Method method = descriptor.getReadMethod();
			return method.invoke(object, new Object[0]);
		} catch (Exception e) {
			Field field = getDeclaredField(object, propertyName);

			Object result = null;
			boolean accessible = field.isAccessible();
			field.setAccessible(true);
			try {
				result = field.get(object);
			} catch (IllegalAccessException e1) {
				logger.info("error wont' happen");
			}
			field.setAccessible(accessible);

			return result;
		}

	}

	/**
	 * 暴力设置对象变量值,忽略private,protected修饰符的限制.
	 * 
	 * @throws BeanAccessException
	 *             如果没有该Field时抛出.
	 */
	public static void setPropertyValue(Object object, String propertyName,
			Object newValue) throws BeanAccessException {
		Assert.notNull(object);
		Assert.hasText(propertyName);
		PropertyDescriptor descriptor;
		try {
			descriptor = new PropertyDescriptor(propertyName, object.getClass());
			Method method = descriptor.getWriteMethod();
			method.invoke(object, new Object[] { newValue });
		} catch (Exception e) {
			Field field = getDeclaredField(object, propertyName);
			boolean accessible = field.isAccessible();
			field.setAccessible(true);
			try {
				field.set(object, newValue);
			} catch (IllegalAccessException e1) {
				logger.info("Error won't happen");
			}
			field.setAccessible(accessible);
		}

	}

	/**
	 * 暴力调用对象函数,忽略private,protected修饰符的限制.
	 * 
	 * @throws BeanAccessException
	 *             如果没有该Method时抛出.
	 */
	public static Object invokePrivateMethod(Object object, String methodName,
			Object... params) throws BeanAccessException {
		Assert.notNull(object);
		Assert.hasText(methodName);
		Class[] types = new Class[params.length];
		for (int i = 0; i < params.length; i++) {
			types[i] = params[i].getClass();
		}

		Class clazz = object.getClass();
		Method method = null;
		for (Class superClass = clazz; superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				method = superClass.getDeclaredMethod(methodName, types);
				break;
			} catch (NoSuchMethodException e) {
				// 方法不在当前类定义,继续向上转型
			}
		}

		if (method == null)
			throw new BeanAccessException("No Such Method:"
					+ clazz.getSimpleName() + methodName);

		boolean accessible = method.isAccessible();
		method.setAccessible(true);
		Object result = null;
		try {
			result = method.invoke(object, params);
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
		method.setAccessible(accessible);
		return result;
	}

	/**
	 * 按Filed的类型取得Field列表.
	 */
	public static List<Field> getFieldsByType(Object object, Class type) {
		List<Field> list = new ArrayList<Field>();
		try {
			Field[] fields = object.getClass().getDeclaredFields();
			for (Field field : fields) {
				if (field.getType().isAssignableFrom(type)) {
					list.add(field);
				}
			}
		} catch (SecurityException e) {
			logger.info("Error won't happen");
		}
		return list;
	}

	/**
	 * 按FiledName获得Field的类型.
	 * 
	 * @throws BeanAccessException
	 *             如果没有该字段时抛出.
	 */
	public static Class getPropertyType(Class type, String name)
			throws BeanAccessException {
		return getDeclaredField(type, name).getType();
	}

	/**
	 * 拷贝属性
	 * 
	 * @param orig
	 *            源对象
	 * @param dest
	 *            目标对象
	 * @throws BeanAccessException
	 *             异常时抛出.
	 */
	public static void copyProperties(Object orig, Object dest)
			throws BeanAccessException {
		try {
			org.apache.commons.beanutils.BeanUtils.copyProperties(dest, orig);
		} catch (IllegalAccessException e) {
			throw new BeanAccessException("IllegalAccessException", e);
		} catch (InvocationTargetException e) {
			throw new BeanAccessException("InvocationTargetException", e);
		}
	}

	// /**
	// * 获得field的getter函数名称.
	// */
	// public static String getGetterName(Class type, String fieldName)
	// {
	// Assert.notNull(type, "Type required");
	// Assert.hasText(fieldName, "FieldName required");
	//
	// if (type.getName().equals("boolean"))
	// {
	// return "is" + StringUtils.capitalize(fieldName);
	// }
	// else
	// {
	// return "get" + StringUtils.capitalize(fieldName);
	// }
	// }
	//
	// /**
	// * 获得field的getter函数,如果找不到该方法,返回null.
	// */
	// public static Method getGetterMethod(Class type, String fieldName)
	// {
	// try
	// {
	// return type.getMethod(getGetterName(type, fieldName));
	// }
	// catch (NoSuchMethodException e)
	// {
	// logger.error(e.getMessage(), e);
	// }
	// return null;
	// }

	/**
	 * 获取声明属性
	 * 
	 */
	public static String[] getDeclaredPropertys(Class clazz) {
		String[] props = null;
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
			PropertyDescriptor[] propertyDescriptors = beanInfo
					.getPropertyDescriptors();
			Vector<String> propVector = new Vector<String>();
			for (PropertyDescriptor propDes : propertyDescriptors) {
				// 如果是class属性 跳过
				if (propDes.getName().equals("class")
						|| propDes.getReadMethod() == null
						|| propDes.getWriteMethod() == null)
					continue;
				propVector.add(propDes.getName());
			}
			props = new String[propVector.size()];
			propVector.toArray(props);
		} catch (IntrospectionException e) {
			logger.error(e.getMessage(), e);
		}
		return props;
	}

	/**
	 * 检测类是否包含属性
	 */
	public static boolean hasProperty(Class clazz, String propertyName) {
		boolean has = false;
		try {
			new PropertyDescriptor(propertyName, clazz);
			has = true;
		} catch (IntrospectionException e) {
			logger.info(clazz.getName() + ":" + e.getMessage());
			return false;
		}
		return has;
	}

	public static PropertyDescriptor[] getPropertyDescriptors(Class clazz) {
		BeanInfo beanInfo = getBeanInfo(clazz);
		return beanInfo.getPropertyDescriptors();
	}

	/**
	 * 根据bean的类取得bean的信息
	 * 
	 * @param clazz
	 * @return
	 */
	public static BeanInfo getBeanInfo(Class clazz) {
		BeanInfo beanInfo = null;
		try {
			beanInfo = Introspector.getBeanInfo(clazz);
		} catch (IntrospectionException e) {
			logger.error(e.getMessage(), e);
		}
		return beanInfo;
	}

	/**
	 * 转化XML格式的到对象
	 * 
	 * @param element
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T convertXmlToObjByAttribute(Class<T> clazz,
			Element element) {
		Object object = null;
		try {
			object = clazz.newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		if (object == null)
			return null;
		// 取得对象所有属性描述信息,根据属性名从xml文件中读取信息
		Iterator iterator = element.elementIterator();
		while (iterator.hasNext()) {
			Element temp = (Element) iterator.next();
			String _propname = temp.attributeValue("name");
			String value = temp.getText();
			setPropertyValue(object, _propname, value);
		}
		return (T) object;
	}

	@SuppressWarnings("unchecked")
	public static <T> T convertXmlToObj(Class<T> clazz, Element element) {
		Object object = null;
		try {
			object = clazz.newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		if (object == null)
			return null;
		// 取得对象所有属性描述信息,根据属性名从xml文件中读取信息
		PropertyDescriptor[] propDescs = BeanUtils
				.getPropertyDescriptors(clazz);
		for (int i = 0; i < propDescs.length; i++) {
			String propname = propDescs[i].getName();
			String value = element.elementText(propname);
			if (value != null && value.trim().length() > 0)
				BeanUtils.setPropertyValue(object, propname, value);
		}
		return (T) object;
	}

	/**
	 * 
	 * 判断字符串为空或者为NULL return true
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isEmpty(String str) {
		return ((str == null) || (str.length() == 0));
	}

	/**
	 * 
	 * 判断对象为空或者为NULL return true
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isEmpty(Object obj) {
		return ((obj == null));
	}

	/**
	 * 判断字符串是否为空或者为NULL 不为空并且不为NULL return true
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNotEmpty(String str) {
		return (!(isEmpty(str)));
	}

	/**
	 * 判断对象是否为空或者为NULL 不为空并且不为NULL return true
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNotEmpty(Object obj) {
		return (!(isEmpty(obj)));
	}
	
	/**
	 * 判断对象是否为空或者为NULL 不为空并且不为NULL return true
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isObjectNotNull(Object obj) {
		if(obj==null ||"".equals(obj)){
			return false;
		}else{
			return true;
		}
	}
	

	/**
	 * 判断字符是否为空或者为NULL 不为空并且不为NULL return 字符 为空返回空-->""
	 * 
	 * @param str
	 * @return
	 */

	public static String getNotNullStr(String str) {
		if (!(isEmpty(str))) {
			return str;
		} else {
			return "";
		}
	}

	/**
	 * 判断字符是否为空或者为NULL 不为空并且不为NULL return 字符 为空返回空-->""
	 * 
	 * @param Date date
	 * @return String
	 */

	public static String getNotNullDate(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		if (date == null) {
			return "";
		} else {
			return sdf.format(date);
		}
	}

	/**
	 * 字符串的比较
	 * 
	 * @param str1,str2
	 * @return
	 */
	public static boolean equals(String str1, String str2) {
		if (str1 == null && str2 != null) {
			return false;
		}
		if (str2 == null && str1 != null) {
			return false;
		}
		if (str1 == null && str2 == null) {
			return false;
		}
		return str1.equals(str2);
	}

	/**
	 * 比较2个字符串，忽略大小写 相等 return true
	 * 
	 * @param str1,
	 *            str2
	 * @return
	 */
	public static boolean equalsIgnoreCase(String str1, String str2) {
		if (str1 == null && str2 != null) {
			return false;
		}
		if (str2 == null && str1 != null) {
			return false;
		}
		if (str1 == null && str2 == null) {
			return false;
		}
		return org.apache.commons.lang.StringUtils.equalsIgnoreCase(str1, str2);
	}

	/**
	 * 页面URL传参时候用到encodeURI转码时后台处理
	 * 
	 * @param str
	 * @return
	 */
	public static String encodeStr(String str)
			throws UnsupportedEncodingException {
		if (isNotEmpty(str)) {
			return java.net.URLDecoder.decode(str, "UTF-8");
		} else {
			return "";
		}
	}
}
